/*
 * file name:drv_w25q128.c
 * version :v1.0.0
 * Change Logs:
 * Date             Author          main change
 * 2023-02-28       lanxin          the first version
 * 2024-01-31       lanxin          fix erase judge err
 *                                  merge drv_w25q128.c and drv_w25q128_fal.c
 *                                  delete drv_w25q128.h
 *
*/

/********************************************* READ ME BEGIN *************************************************************/

/* Brief:
 *
 * *1.使用 SFUD 接口读写 FLASH。
 *
 * *2.使能 FAL 时，提供相关接口。
 * 
 */

/* Notice:
 *
 * *1.读写前应调用初始化函数。
 *
 */

/********************************************* READ ME END ***************************************************************/

/* source file */
#include "rtthread.h"
#include <sfud.h>
#include <spi_flash_sfud.h>
#include "drv_spi.h"

/* private define */

#define W25QXX_FLASH_DEV_NAME   "w25q128"

#define W25QXX_SPI_BUS_NAME     "spi2"
#define W25QXX_SPI_NAME         "spi20"

/* 片选引脚 */
#define W25QXX_CS_PORT  GPIOB
#define W25QXX_CS_PIN   GPIO_PINS_12

/* function declaration */
static int _w25qxx_init ( void );
static int _w25qxx_read ( long offset, uint8_t *buf, size_t size );
static int _w25qxx_write ( long offset, const uint8_t *buf, size_t size );
static int _w25qxx_erase ( long offset, size_t size );

/* variable declaration */
static sfud_flash_t sfud_dev = NULL;

static int w25qxx_max_len = 0;
static rt_uint8_t w25qxx_ready = 0;

#ifdef RT_USING_FAL

#include "fal.h"

struct fal_flash_dev spi_flash =
{
    .name       = "spiflash",
    .addr       = 0,//起始地址
    .len        = 16*1024 * 1024, //总容量16MB
    .blk_size   = 4096,//存储块大小
    .ops        = {_w25qxx_init, _w25qxx_read, _w25qxx_write, _w25qxx_erase},
    .write_gran = 1,
};

#endif/* RT_USING_FAL */

/*
 * *@ author:lanxin
 * *@ brief:flash的初始化接口
 * *@ note:需要完成SFDD的探测操作，并将设备名设置为 FAL_DATA_FLASH_DEV_NAME
 * *@ param:NONE
 * *@ retval:result
 * -- 0 成功
 * -- -1失败
 */
static int _w25qxx_init ( void )
{
    /* 挂载 spi 设备 */
    rt_hw_spi_device_attach ( W25QXX_SPI_BUS_NAME, W25QXX_SPI_NAME, W25QXX_CS_PORT, W25QXX_CS_PIN );

    /* 使用 SFUD 探测 FLASH 设备 */
    if ( RT_NULL == rt_sfud_flash_probe ( W25QXX_FLASH_DEV_NAME, W25QXX_SPI_NAME ) )
    {
        return -1;
    }

    /* 查找设备 */
    sfud_dev = rt_sfud_flash_find_by_dev_name ( W25QXX_FLASH_DEV_NAME );

    if ( RT_NULL == sfud_dev )
    {
        return -1;
    }

    /* 同步存储总容量 */
    w25qxx_max_len = sfud_dev->chip.capacity;

    w25qxx_ready = 1;

    return 0;
}
/*
 * *@ author:lanxin
 * *@ brief:flash的读数据接口
 * *@ note:
 * *@ param:offset 读取数据地址的偏移量
 * *@ param:buf 保存读取出来的数据的数据指针
 * *@ param:size 读取的数据个数
 * *@ retval:
 * -- 要读取的数据个数
 * -- 0x00 读取失败
 */
static int _w25qxx_read ( long offset, uint8_t *buf, size_t size )
{
    RT_ASSERT ( sfud_dev );
    RT_ASSERT ( sfud_dev->init_ok );

    /* 通过SFUD 读取数据*/
    if ( w25qxx_ready && w25qxx_max_len >= offset + size )
    {
        sfud_read ( sfud_dev, offset, size, buf );

        return size;
    }

    return 0x00;
}
/*
 * *@ author:lanxin
 * *@ brief:flash的写数据接口
 * *@ note:
 * *@ param:offset 写入数据地址的偏移量
 * *@ param:buf 写入的数据指针
 * *@ param:size 写入的数据个数
 * *@ retval:
 * -- -1 写入失败
 * -- 其他成功
 */
static int _w25qxx_write ( long offset, const uint8_t *buf, size_t size )
{
    RT_ASSERT ( sfud_dev );
    RT_ASSERT ( sfud_dev->init_ok );

    if ( w25qxx_ready == 0 || w25qxx_max_len < offset + size )
    {
        return -1;
    }

    /* 通过SFUD写入数据 */
    if ( sfud_write ( sfud_dev, offset, size, buf ) != SFUD_SUCCESS )
    {
        return -1;
    }

    return size;
}
/*
 * *@ author:lanxin
 * *@ brief:flash的擦除数据接口
 * *@ note:
 * *@ param:offset 擦除数据地址的偏移量
 * *@ param:size 擦除的数据个数
 * *@ retval:
 * -- -1 擦除失败
 * -- 其他成功
 */
static int _w25qxx_erase ( long offset, size_t size )
{
    RT_ASSERT ( sfud_dev );
    RT_ASSERT ( sfud_dev->init_ok );

    if ( w25qxx_ready == 0 || w25qxx_max_len < offset + size )
    {
        return -1;
    }

    /* 通过SFUD擦除数据 */
    if ( sfud_erase ( sfud_dev, offset, size ) != SFUD_SUCCESS )
    {
        return -1;
    }

    return size;
}
